package org.fujay.langchain4jserver.domain.model.aggregate;

import lombok.*;
import org.fujay.commons.langchain4j.core.enumd.ResponseFormatEnum;
import org.fujay.commons.langchain4j.core.options.LlmOptions;
import org.fujay.langchain4jserver.domain.model.vo.*;
import org.fujay.langchain4jserver.domain.shared.exception.DomainException;

import java.time.LocalDateTime;

/**
 * 模型聚合根
 */
@Getter
@Setter(AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Model {

    @NonNull
    private ModelId id;

    @NonNull
    private String modelName;

    @NonNull
    private ModelType modelType;

    @NonNull
    private SupplierInfo supplier;

    @NonNull
    private ModelConfig config;

    @NonNull
    private ConnectionStatus connectionStatus;

    private boolean enabled;

    private LocalDateTime createTime;
    private LocalDateTime updateTime;

    /**
     * 创建模型领域
     */
    public static Model create(
            ModelId id,
            String modelName,
            ModelType modelType,
            SupplierInfo supplier,
            ModelConfig config) {
        return new Model(
                id,
                modelName,
                modelType,
                supplier,
                config,
                ConnectionStatus.initial(),
                false,
                LocalDateTime.now(),
                LocalDateTime.now());
    }

    /**
     * 静态加载方法，用于从持久化状态重建聚合根
     *
     * @param id               模型ID
     * @param modelName        模型名称
     * @param modelType        模型类型
     * @param supplier         供应商信息
     * @param config           模型配置
     * @param enabled          是否启用
     * @param connectionStatus 连接状态
     * @param createTime       创建时间
     * @param updateTime       更新时间
     * @return 重建的模型聚合根实例
     */
    public static Model load(
            ModelId id,
            String modelName,
            ModelType modelType,
            SupplierInfo supplier,
            ModelConfig config,
            boolean enabled,
            ConnectionStatus connectionStatus,
            LocalDateTime createTime,
            LocalDateTime updateTime) {
        // 直接调用私有构造函数来重建状态
        return new Model(
                id,
                modelName,
                modelType,
                supplier,
                config,
                connectionStatus,
                enabled,
                createTime,
                updateTime);
    }

    /**
     * 更新模型配置时，初始化模型连接状态
     */
    public void updateConfig(ModelConfig newConfig) {
        this.config = newConfig;
        this.connectionStatus = ConnectionStatus.initial();
        this.enabled = false;
        this.updateTime = LocalDateTime.now();
    }

    // 更新模型基础信息
    public void updateBasicInfo(String modelName, ModelType modelType, SupplierInfo supplier) {
        this.modelName = modelName;
        this.modelType = modelType;
        this.supplier = supplier;
        this.updateTime = LocalDateTime.now();
    }

    // 记录连接测试结果
    public void recordConnectionTest(TestResult result) {
        this.connectionStatus = this.connectionStatus.recordTestResult(result);
        // 如果测试失败，则禁用
        if (result == TestResult.FAILED) {
            this.enabled = false;
        }
        this.updateTime = LocalDateTime.now();
    }

    // 启用模型
    public void enable() {
        if (this.connectionStatus.lastTestResult() != TestResult.SUCCESS) {
            throw new DomainException("启用模型前必须先通过连接测试");
        }
        if (this.enabled) {
            return;
        }
        this.enabled = true;
        this.updateTime = LocalDateTime.now();
    }

    // 禁用模型
    public void disable() {
        if (!this.enabled) {
            return;
        }
        this.enabled = false;
        this.updateTime = LocalDateTime.now();
        // 可以在这里发布 ModelDisabledEvent
    }

    /*辅助方法，通过Model构造LLMOptions*/

    public LlmOptions convertToLlmOptions() {
        LlmOptions options = new LlmOptions();

        // BaseOptions mapping
        options.setSupplier(supplier.supplierCode());
        options.setModelName(modelName);
        options.setBaseUrl(config.baseUrl());
        options.setApiKey(config.apiKey());
        options.setApiSecret(config.secretKey());
        options.setLogRequests(config.logRequests());
        options.setLogResponses(config.logResponses());
        if (config.responseFormat() == 1) {
            options.setResponseFormat(ResponseFormatEnum.JSON_OBJECT);
        } else {
            options.setResponseFormat(ResponseFormatEnum.TEXT);
        }

        // LlmOptions specific mapping
        options.setTemperature(config.temperature());
        options.setTopK(config.topK());
        options.setTopP(config.topP());
        options.setMaxCtx(config.numCtx()); // Map numCtx to maxCtx
        options.setMaxTokens(config.maxTokens());
        options.setMaxMemory(config.maxMemory());

        return options;
    }
}
